Module Mission Templates

Tuple Documentation of module_mission_templates.py
Each mission-template is a tuple that contains the following fields:
1) Mission-template id (string): used for referencing mission-templates in other files.
    The prefix mt_ is automatically added before each mission-template id
2) Mission-template flags (int): See header_mission_templates.py for a list of available flags
3) Mission-type(int): Which mission types this mission template matches.
    For mission-types to be used with the default party-meeting system,
    this should be 'charge' or 'charge_with_ally' otherwise must be -1.
4) Mission description text (string).
5) List of spawn records (list): Each spawn record is a tuple that contains the following fields:
5.1) entry-no: Troops spawned from this spawn record will use this entry
5.2) spawn flags.
5.3) alter flags. which equipment will be overriden
5.4) ai flags.
5.5) Number of troops to spawn.
5.6) list of equipment to add to troops spawned from here (maximum 8).
6) List of triggers (list).
    See module_triggers.py for infomation about triggers.

The file module_mission_templates.py contains the Mission Templates. Mission templates are sets of scripts that govern different events known as missions, in simple terms. They can range from simple quests to complex battles with reinforcements.[1] If you need to test outcomes of combat, this is the file you will need to work in.

Anytime you have a confrontation battle, these code blocks are checked. You can also set up what macro keys (such as TAB) will do during the battle. Before the meat of the mission templates, a bunch of local constants are set. The first two are designed as item overrides. We will see more on this later, but if you are picking up the workings of the Module System, you should understand what they do. Next you will see some other longer tuple constants, such as common_battle_mission_start. You should recognize the format of these constants. They look just like tuples from module_triggers.py. This is because they are triggers. As you can see in the header of module_mission_templates.py, the sixth part of these tuples are triggers. By defining some common triggers at the top as constants, you will not have to type these triggers for each tuple that will need them.

At about line 1275, you will see the start of the mission templates, mission_templates = [. Let's look at the breakdown of the first mission template tuple "town_default" as defined in this file's header:

								
									1. Mission template ID (prefixed with mt_) = "town_default"
2. Flags (as defined in header_mission_template.py) = 0
3. Mission Type interger. Should be 'charge' or 'charge_with_ally' otherwise must be -1 = -1
4. Mission description text = "Default town visit"
5. List of spawn records (list). Breakdown of the list (entry-no spawn point, spawn flags, alter/equipment override flags, AI flags, number of troops to spawn, list of equipment to add to troops spawned here with a maximum of eight items) =
 [
 (0,mtef_scene_source|mtef_team_0,af_override_horse,0,1,pilgrim_disguise),
...
 (7,mtef_scene_source|mtef_team_0,af_override_horse,0,1,[]),
 (8,mtef_scene_source,af_override_horse,0,1,[]),
...
 (12,mtef_scene_source,af_override_horse,0,1,[]),
 (13,mtef_scene_source,0,0,1,[]),
 (14,mtef_scene_source,0,0,1,[]),
 (15,mtef_scene_source,0,0,1,[]),
 (16,mtef_visitor_source,af_override_horse,0,1,[]),
...
 (31,mtef_visitor_source,af_override_horse,0,1,[]),
 ],
6. List of triggers (see module_triggers.py for format on triggers) =
 [
 (1, 0, ti_once, [], [
   (store_current_scene, ":cur_scene"),
   (scene_set_slot, ":cur_scene", slot_scene_visited, 1),
   (try_begin),
       (eq, "$sneaked_into_town", 1),
       (call_script, "script_music_set_situation_with_culture", mtf_sit_town_infiltrate),
   (else_try),
       (eq, "$talk_context", tc_tavern_talk),
       (call_script, "script_music_set_situation_with_culture", mtf_sit_tavern),
   (else_try),
       (call_script, "script_music_set_situation_with_culture", mtf_sit_travel),
   (try_end),
 ]),
 (ti_before_mission_start, 0, 0, [], [(call_script, "script_change_banners_and_chest")]),
 (ti_inventory_key_pressed, 0, 0, [(set_trigger_result,1)], []),
 (ti_tab_pressed, 0, 0, [(set_trigger_result,1)], []),
 ],
),

Mission Template Flags

The following mission template flags are available for usage:

mtf_arena_fight triggers the identification of enemies through team_no.
mtf_battle_mode prevents that the player has inventory access (via the game key for the Inventory Window).
mtf_commit_casualties Up4research
mtf_no_blood disables blood in the mission.
mtf_synch_inventory triggers a backup of player inventory at the mission start and restores it at the mission end.
mtf_team_fight equivalent to mtf_arena_fight.

Mission Types

Native lists the following mission types as available for usage:
cancel_attack, cancel_reinforce, charge, charge_with_ally, intend_battle, leave_during_battle, leave_wo_battle, speak, stay_back, stay_back_with_ally, surrender.

However, they are all deprecated, including charge and charge_with_ally. The game engine will ignore any value at this field.

Spawn Records

								
									  [  ( 1 ,mtef_ defenders ,0, group(1)|aif_start_alarmed ,8,[]),
      ^ Entry number
    ( 0 , mtef_defenders ,0, group(1)|aif_start_alarmed ,0,[]),
                ^ Who spawns here
    ( 4 , mtef_attackers ,0, aif_start_alarmed ,8,[]),
                                  ^ How do they behave
    ( 4 , mtef_attackers ,0, aif_start_alarmed ,0,[]),
                                                ^ How many spawn
  ],

Need to explain it better Work in notes of Mirathei, Modding Q&A. Also note of Khamu about mission template entry and spawn record, Mount & Blade Modding Discord. The single parts will get explained in more details at the upfollowing sections.

entry point vs spawn record, kalarhan, Modding Q&A

Spawn/Entry Flags

After the spawn entry points, you need to set the spawn/entry flags. The first flag sets the confrontation style, also called 'filter flags' in header_mission_templates. This can be for example mtef_attackers or mtef_defenders, the flags for field encounters. Attackers would be the party initiating the encounter, the defender would be the other party. Multiple flags are divided by a |. All available flags are given in the list below:

mtef_ally_party not used in Native, Up4research.
mtef_archers_first gives archers troops of the party priority at spawning as first ones at this entry point(?).
mtef_attackers sets the spawned troop to be part of the party which initiated the encounter(?).
mtef_cavalry_first gives cavalry troops of the party priority at spawning as first ones at this entry point(?).
mtef_conversation_source not used in Native, Up4research.
mtef_defenders sets the spawned troop to be part of the party which got encountered(?).
mtef_enemy_party not used in Native, Up4research.
mtef_infantry_first gives infantry troops of the party priority at spawning as first ones at this entry point(?).
mtef_leader_only bundels mtef_no_companions and mtef_no_regulars so that only the leader of a party spawns at this entry point(?).
mtef_no_auto_reset if you want to move entry points you have to mark them as mtef_no_auto_reset. Otherwise they will "auto reset" every ten frames.[2]
mtef_no_companions prevents companions of parties to spawn at this entry point(?).
mtef_no_leader prevents leaders of parties to spawn at this entry point(?).
mtef_no_regulars prevents regulars of parties to spawn at this entry point(?).
mtef_regulars_only bundels mtef_no_leader and mtef_no_companions so that only regulars of a party spawn at this entry point(?).
mtef_reverse_order spawns troops in reverse order regarding to their sorting at the party(?).
mtef_scene_source is used for troops that have a site/entry point defined statically (see tuple field 5 at module_troops.py). It spawns them on the first frame of the mission only if the entry point defined in the tuple has the flag.[3]
mtef_team_X sets that the spawned troop would be part of team X, with X being within the range of 0 to 5.
mtef_team_member_2 not used in Native, Up4research.
mtef_use_exact_number lets the exact number of troops spawn here which are declared at a later part of the spawn record.
mtef_visitor_source is used for adding visitors to the site on the fly. It enables the usage of the operation add_visitors_to_current_scene at this entry point.[3]

Alter Flags

We now look at the alter flags. These are set to override certain items that may not be allowed in this mission. If it would be more sporting to fight on foot at your planned mission, you will want to override horses. All available flags are given in the list below:

af_override_weapons overrides all weapons.
af_override_weapon_0 overrides the weapon in equipment slot 0.
af_override_weapon_1 overrides the weapon in equipment slot 1.
af_override_weapon_2 overrides the weapon in equipment slot 2.
af_override_weapon_3 overrides the weapon in equipment slot 3.
af_override_head overrides the helmet in equipment slot 4.
af_override_fullhelm overrides the helmet in equipment slot 4 if the item entry of the helmet has the flag itp_covers_head.[4]
af_override_body overrides the armour in equipment slot 5.
af_override_foot overrides the footwear in equipment slot 6.
af_override_gloves overrides the gloves in equipment slot 7.
af_override_horse overrides the horse in equipment slot 8.
af_override_everything bundles some alter flags such way that everything gets overriden.
af_override_all bundles some alter flags such way that everything except the footwear gets overriden.[5]
af_override_all_but_horse bundles some alter flags such way that everything except the footwear and the the horse gets overriden.[5]
af_require_civilian lets the hero-troop only wear items with the flag itp_civilian.

AI flag

The next flag is the AI flag. A look into module_mission_templates.py shows you that in the most cases it is set to aif_start_alarmed which makes the AI ready to fight. Otherwise it is set to 0. After this you set the number of troops to spawn.

Equipment after Override

The last part of the list (inside the []) is for equipment to add to the troops spawned here, to a maximum of 8 items. If you override all other equipment the troop will pick from what is listed here. If you want the troop spawning here to have a choice between a wooden staff or a wooden sword for example, override all equipment and add the aforementioned items, to be randomly chosen.

Check for missing informations.

Mission Template Triggers [6]

simple triggers, triggers and mission templates explained, taking over the other passages to the other sections, Lumos, Modding Q&A.

A trigger in mission templates (and in module_triggers.py for that matter) takes the following form:

  • First Part: how often the trigger is checked, either in seconds[7] or as a hard-coded event such as ti_on_agent_hit.
  • Second Part: the delay, in seconds[7], between reading the conditions block and executing the consequences block. This does not work if you are using a 'word'/hard-coded event interval, such as ti_on_agent_hit
  • Third Part: the re-arm delay, in seconds[7], between when the consequences block was finished and when the trigger can be checked again. A special re-arm delay ti_once is used for triggers that should only complete themselves (have their condition pass and then execute their consequence) once and then never fire again. Neither ti_before_mission_start nor ti_after_mission start need ti_once in their re-arm delay as they will only ever fire one time.
  • Fourth Part: the conditions block, always executed when the trigger is called.
  • Fifth Part: the consequences block, only executed if the conditions block does not fail, and after the delay interval has passed.

In practice, it looks like this:

								
									  (10, 2, 60,
    [
     (eq, 1, 1),
    ],
    [
     (val_add, "$global_variable", 10),
    ]),

In this instance, the check interval is every 10 seconds, so the trigger will be checked every 10 seconds. The delay interval is 2 seconds, so if the conditions block is true, the consequences block will fire 2 seconds later. The re-arm interval is 60 seconds, so after the conditions block is found to be true, it will be one minute until this trigger can be checked again.

The conditions block is a simple equality test, 1==1, that will always pass, so the consequences block will always fire 2 seconds after the trigger is checked. The consequences block then takes a global variable and increments it by 10.

Timed Triggers

Understanding the check interval/delay/re-arm intervals of timed triggers can be tricky, so here is an illustration:

								
									(2, 1, 3, [<a condition that sometimes fails, sometimes passes>],
  [
   #some consequences
  ]),

This trigger, like all timed triggers with a check interval >0, will start to be checked around the first 1 second of the mission:

Second Event
1 Trigger checked; condition fails--apply check interval (+2 seconds)
3 Trigger checked; condition fails--apply check interval (+2 seconds)
5 Trigger checked; condition passes--apply consequence delay (+1 second)
6 Consequence fires and completes--apply check interval (+2 seconds); apply re-arm delay (+3 seconds)
11 Trigger checked; condition fails--apply check interval (+2 seconds)
13 Trigger checked; condition passes--apply consequence delay (+1 second)
14 Consequence fires and completes--apply check interval (+2 seconds); apply re-arm delay (+3 seconds)
19 Trigger checked....

So, although we have specified a check interval of 2 seconds, we see that the trigger is not checked only on even seconds; instead it is checked in seconds 1, 3, 5, 11, 13, 19.

If one wants a completely "scheduled" trigger, both consequence and re-arm delays cannot be used.

Two Triggers of Same Type/Interval

When there are two triggers that have the same check interval (be that in seconds, or on an event ti_*) the order they appear in the mission template matters. The trigger that appears first in the template will fire first, followed by the next trigger of the same interval, and so on. That means if you have two triggers that fire at ti_on_agent_spawn, the one that appears in the file first will execute before the second one.

Triggers Near Beginning of Mission

Logically, the trigger ti_before_mission_start takes place before the scene is set up and before agents are spawned into the scene.[8] Next, spawning takes place before any other triggers fire - ti_on_agent_spawn triggers are the only triggers firing at this point. Next, ti_after_mission_start triggers fire, as well as any triggers with a check interval of 0 (every frame) as the mission timer starts. Event-based triggers will not be called until their ti_* event occurs; other timed triggers begin being called somewhere in the first second of the mission, though after ti_after_mission_start triggers and every frame (check interval 0) triggers.

If you have triggers that do not need to fire that close to mission start, adding something like

								
									(store_mission_timer_a, reg0),(gt, reg0, <second-to-start-checking>),
								
							

to the conditions block will help ease the CPU load at mission start.

To summarize, at the start of a mission we have:

  • ti_before_mission_start
  • Spawning-- (ti_on_agent_spawn)
  • Time Begins--
  • ti_after_mission_start & triggers with check intervals of "0" (which fire at a mission time of approximately 0.2 seconds)
  • Timed Triggers (still within the first 1 second of the mission)
  • Event-based triggers

Create list of event-based mission template triggers

Semi-randomness of Triggers

Some stuff about semi-randomness, MadocComadrin and Caba`drin, Modding Q&A

Other Notes

ti on item wielded is mp only, Somebody, Modding Q&A. I saw it in singleplayer mission templates too though, not sure if working at both now or not.

The problem is, for throwing weapons and with the ti_on_agent_hit trigger, the weapon can will fly through people and hit multiple people, SonKidd, Modding Q&A. As always, one modder's bug can be another modder's feature.

equivalent triggers, Caba`drin, Modding Q&A

rearms and delays at named triggers, cmpxchg8b, Modding Q&A; no delay and no rearm for specific triggers, Somebody, Modding Q&A, and kalarhan, Modding Q&A; timed triggers and event triggers (named triggers), Vornne, Modding Q&A.

trigger check interval, kalarhan, Modding Q&A.

Jumping from Mission Template to Mission Template [9]

There might come up a situation at your modding project at which you would like to switch from a scene to another scene without any menu between. This could be because of the plot or story driven basics of your mod or because you want to design a special scenario appears in the player's campaign. Now you cannot make a simply jump at the end of the mission template since after the mission terminates, the game will send the players to the game menu that was first loaded when they encountered the map party. For example if it was a town, they get booted back to the town menu. At that point you could cause a new scene to be loaded.

The solution here is however to basically just move the 'jump_mission'-operations to the conditions block. Then the players can jump straight from one mission to another. For this, change your triggers to look similar to the following example:

								
									  (1, 60, ti_once,
  [
    (store_mission_timer_a,reg(1)),
    (ge,reg(1),10),
    (all_enemies_defeated,2),
    (neg|main_hero_fallen),
    (set_mission_result,1),
    (assign,"$battle_won",1),
    (set_jump_mission,"mt_force_conversation"),
    (assign,"$other_char","$other_char_win"),
    (jump_to_scene,"$other_scene_win"),
    (change_screen_mission),
  ],[]),

  (1, 4, ti_once,
  [
    (main_hero_fallen),
    (set_jump_mission,"mt_force_conversation"),
    (assign,"$other_char","$other_char_lose"),
    (jump_to_scene,"$other_scene_lose"),
    (assign,"$player_lost",1),
    (change_screen_mission),
  ],[]),

Battle Size

Work in the informations of the threads of kalarhan, Modding Q&A and Modding Q&A. See also the issue note at the header operations GitLab for the explanations of Vetrogor.

Weather

Some weather info bits, Caba`drin, Modding Q&A

random rain at scene, Roemerboy, Modding Q&A

It can't rain and snow at the same time, Somebody, Modding Q&A

multiplayer weather, Somebody, Modding Q&A

crossbows shoot bad at fog via engine? Somebody, Modding Q&A and Modding Q&A

basic principles of using weather in a scene, Abhuva, Nordous' Sceners Guild

yellow fog instead of black, Somebody, Modding Q&A

low fog value probably due to yellow fog problem? Marko, Modding Q&A

weather stuff, Sim00n (credit), Modding Q&A

change skybox for scene (not sure atm if weather or mission template), kalarhan, Modding Q&A

paint skybox, kalarhan, Modding Q&A

mp weather stuff, Namakan (credit), Modding Q&A, and _Sebastian_, Modding Q&A

weather in edit mode just for preview, _Sebastian_, Modding Q&A

setting weather, _Sebastian_, Modding Q&A

remove fog from scene, Dj_FRedy, Modding Q&A

Problems with fog, Modding Q&A and Modding Q&A

global cloud amount sets fog too, Khamukkamu, Modding Q&A

skyboxes daytime, Ruthven, Modding Q&A

Darker nights, Pitch, Modding Q&A

Global cloud amount, cmpxchg8b, Modding Q&A

Weapon and Damage Systems

Hit Detection

The game engine checks the collision between one of target's hitboxes with the attacker's right item bone. For latter it uses a capsule attached to the right item bone. The game engine references not the right item bone by name but by a hard-coded index, it's the 19th bone.[10]

Melee Weapon Bounce

When striking an enemy the player might experience that the melee weapon bounces and the thrust gets repulsed. There are multiple factors which can influence this, so the following might be an incomplete list:[11]

  1. The "business end" of a weapon is either a line or a long capsule running down the weapon's length, which deals damage if it collides with an agent hitbox.
  2. Weapons bounce if
    • the velocity of collision is too low,
    • the weapon's "business end" hits the hitbox at an odd angle relative to the attacker, like spinstabbing,
    • the weapon doesn't do enough damage or
    • the "shaft" hits the hitbox (how the game determines shafts is unknown)
  3. Weapons also bounce depending on weapon type and length. There seems to be a lot more lenience to short weapons regarding the "shaft" but at the same time polearms seem to get less lenience than weapons of the same length defined as swords. This is just an observance though, it is untested.
  4. All this is based on the animations. This allows custom attack animations to affect the combat model.

Kicking

A kick is an area-of-effect (AOE) attack for which the game engine checks for the agent in front of the kicker.[12] You cannot change the range of a kick, it is hard-coded into the game.[13] The game supports up to three kick variations:[14]

  1. When the player clicks the E-button while blocking, it will start from the animation "prepare_kick_0", otherwise :
  2. When the player clicks the E-button while moving forward, it will start from the animation "prepare_kick_1", otherwise :
  3. It will start from the animation "prepare_kick_2"

With help of scripts and triggers it should be possible to rework "prepare_kick_0" as shieldbash or left punch (use the same animation, then use on hit event and check for the left hand item to differentiate between them). "prepare_kick_1" and "prepare_kick_2" can then still be used as normal kicks with different animations.

Damage Formulas

Game engine formula for damage calculation:[15]

								
									if hold_time >= 1.1
    hold_bonus = 1.2
elif hold_time >= 0.6:
    hold_bonus = (1.1 - hold_time) * 0.6 + 1.2
elif hold_time >= 0.5:
    hold_bonus = 1.5
else:
    hold_bonus = hold_time + 1.0

raw_damage = weapon_damage * (clamp(hold_bonus, 1.0, 2.0) * 0.5 + 0.5)

if weapon_type == 'one_handed' or weapon_type == 'two_handed' or weapon_type == 'polearm':
    raw_damage *= math.pow(melee_damage_speed_power, speed_bonus)
elif weapon_type == 'crossbow' or weapon_type == 'bow' or weapon_type == 'throwing':
    raw_damage *= math.pow(missile_damage_speed_power, speed_bonus)

if weapon_type == 'crossbow':
    if raining:
        raw_damage *= 0.75
else:
    raw_damage *= proficiency * 0.01 * 0.15 + 0.85

if weapon_type == 'bow':
    raw_damage *= min(power_draw, difficulty + 4) * 0.14 + 1

    if mounted:
        raw_damage *= horse_archery * 0.019 + 0.8

    if raining:
        raw_damage *= 0.9
elif weapon_type == 'throwing':
    raw_damage *= power_throw * 0.1 + 1.0

    if mounted:
        raw_damage *= horse_archery * 0.019 + 0.8
elif weapon_type == 'one_handed' or weapon_type == 'two_handed' or weapon_type == 'polearm':
    raw_damage *= power_strike * 0.08 + 1.0

    raw_damage += strength / 5.0

    if (weapon_type == 'two_handed' or weapon_type == 'polearm') and (has_shield or mounted):
        raw_damage *= 0.85

        if weapon_type == 'polearm':
            raw_damage *= 0.85

        if weapon_flags & itp_two_handed:
            raw_damage *= 0.9

raw_damage = clamp(raw_damage, 0, 500)

While you can assign a maximum damage value of 255 to any item stat within module_items.py, the last line of the damage formula indicates that the normal damage cap is at 500. This is due to the various other conditions which influence the damage in a positive (or negative) way, as given by the damage formula above. Examples for this are skills, proficiencies or the speed of the weapon at a specific moment. However, the normal damage cap of 500 can be bypassed by using the trigger ti_on_agent_hit and setting the prefered damage value within it via set_trigger_result.

Game engine formula for dealing out damage:[15]

								
									armor = appropriate_armor_value_for_hit_location

if hit_shield_on_back:
armor += shield_resistance + 10

soak_factor = armor * module.ini_soak_factor_for_damage_type
reduction_factor = armor * module.ini_reduction_factor_for_damage_type

if item_flags & itp_extra_penetration:
soak_factor *= module.ini_extra_penetration_soak_factor
reduction_factor *= module.ini_extra_penetration_reduction_factor

randomized_soak = (random.random() * 0.55 + 0.45) * soak_factor
randomized_damage = (random.random() * 0.1 + 0.9) * raw_damage
soaked_damage = randomized_damage - randomized_soak

if (soaked_damage < 0.0):
soaked_damage = 0.0

randomized_reduction = math.exp((random.random() * 0.55 + 0.45) * reduction_factor * 0.014)
reduced_damage = (1.0 - 1.0 / randomized_reduction) * soaked_damage

if (reduction_factor < 0.00001):
reduced_damage = 0.0

damage_difference = round(reduced_damage + randomized_soak)
effective_damage = randomized_damage - damage_difference

if hit_bone == head:
effective_damage *= 1.2

if item_is_ranged:
effective_damage *= 1.75
elif hit_bone == calf or hit_bone == thigh:
effective_damage *= 0.9

effective_damage = clamp(effective_damage, 0.0, 500.0)

Chance for Crippling or Killing Horses

When horses "die" in-battle while being ridden by the player there is a random chance for it to be crippled or killed after the battle. You cannot increase or decrease the chance for that, it is hard-coded into the game engine. You can still write a script that does a similar thing by checking and replacing the horse's item modifiers after a mission and create thus a workaround for it.[16]

Weapon Speed Formula

Game engine formula for the weapon speed:[17]

								
									float mbAgent::getActionSpeed(int hand, bool reloading)
{
    mbItem item;
    item.m_itemKindNo = -1;

    if (reloading)
    {
        const mbItem *temp = getItem(hand);
        if (temp)
            item = *temp;
    }
    else
    {
        item = getWieldedItem(hand);
    }

    if (!item.isValid())
        return 1.0f;

    mbItemKind *itemKind = item.getItemKind();
    int type = itemKind->getType();
    mbItem secondaryItem = getWieldedItem(ah_secondary);
    float speed = itemKind->getSpeedRating() * 0.01f;

    if (itemKind->isWeapon())
    {
        float weaponFactor = type == itp_type_bow ? 0.11f : 0.07f;

        speed *= 0.01f * (int)getTroop()->getProficiency(itemKind->getProficiency(secondaryItem.isValid())) * weaponFactor + 1.0f - weaponFactor;
    }

    if (type == itp_type_two_handed || type == itp_type_polearm)
    {
        if (secondaryItem.isValid() || hasMount())
        {
            speed -= 0.15f;

            if (itemKind->m_properties & itp_two_handed)
                speed -= 0.05f;
        }
    }
    else if (type == itp_type_shield)
    {
        speed *= g_game->getTroopSkill(m_troopNo, skl_shield, true) * 0.03f + 1.0f;
    }

    if (g_basicGame.isMultiplayer())
        speed *= 0.03f * g_networkManager.m_combatSpeed + 0.94f;
    else if (itemKind->isMeleeWeapon() && (m_no != g_mission->m_playerAgentNo || rglConfig::Battle::iCombatSpeed > 2))
        speed *= 0.03f * rglConfig::Battle::iCombatSpeed + 0.94f;

    return speed;
}

Shot Speed/Missile Starting Velocity Formula

The game engine formula for the shot speed is as follows:[18]

								
									ingame_velocity_in_m_per_s = item_kinds_shoot_speed * sqrt((PD * 0.12) + 1.0) * 1.2
{PD capped at bow diff+4}

All missile speeds are (for unknown reasons) getting multipiled by 1.2, it does not matter which weapon type, except for missiles which are shot with the operation add_missile. Bow- and throwing shot speeds are also modified by power draw or power throw.[19]

The engine applies quadratic drag to missiles and the drag factors are defined in module.ini:[20]

								
									air_friction_arrow = 0.002
air_friction_bullet = 0.002

Missile Speed Formula

Game engine formula for the missile speed:[21]

								
									float mbAgent::getMissileSpeed()
{
    float missileSpeed = 10.0f;
    float speedFactor = 1.0f;
    mbItem item = getWieldedItem(ah_primary);

    if (item.isValid())
    {
        mbItemKind *itemKind = item.getItemKind();

        missileSpeed = (float)itemKind->getMissileSpeed();

        if (itemKind->getType() == itp_type_bow)
        {
            speedFactor = rglMin(g_game->getTroopSkill(m_troopNo, skl_power_draw, true), item.getDifficulty() + 4) * 0.12f + 1.0f;

            if (m_horseAgentNo != -1)
                speedFactor *= g_game->getTroopSkill(m_troopNo, skl_horse_archery, true) * 0.019f + 0.8f;

            if (g_mission->m_weather.m_precipitationType == wpr_rain)
                speedFactor *= 0.9f;
        }
        else if (itemKind->getType() == itp_type_crossbow)
        {
            if (g_mission->m_weather.m_precipitationType == wpr_rain)
                speedFactor *= 0.75f;
        }
        else if (itemKind->getType() == itp_type_thrown)
        {
            speedFactor = g_game->getTroopSkill(m_troopNo, skl_power_throw, true) * 0.1f + 1.0f;

            if (m_horseAgentNo != -1)
                speedFactor *= g_game->getTroopSkill(m_troopNo, skl_horse_archery, true) * 0.019f + 0.8f;
        }
    }

    return rglSqrt(speedFactor) * missileSpeed * 1.2f;
}

Maximum Speed and Acceleration Formulas

Game engine formulas for the maximum speed and acceleration:[22]

								
									maxSpeed *=1 ((agility * 0.7f + athletics * 3.0f + 25.0f) * 70.0f / (equippedItemsWeight + wieldedItemWeight * wieldedItemLength * 2.5 + 70.0f) + 90.0f) / 100.0f
maxAcceleration = ((athletics / 6.0f + (agility + 2.0f) / 15.0f) * 40.0f / (equippedItemsWeight + 40.0f) + 1.0f) * 70.0f / (equippedItemsWeight + 70.0f) * 5.0f

Weapon Switch System

You might want to change the way a character switches from a weapon to another, for example such way that the first equipped weapon should be put away automatically with an animation and the character draws afterwards the other weapon. The behaviour in Warband is however hard-coded. The only way might be to put something together by playing animations in the ti_on_item_wielded and ti_on_item_unwielded triggers.[23]

Ammo Drop and Pick Up

When you drop a bow, crossbow or firearm, you also drop the ammunition. This is a hard-coded behaviour of the game engine. However, you can give the agent a new bag of ammunition when the item is dropped via the usage of triggers. An appearing problem might then be that the player can just pick up the old ammo again unless you give it a flag.[24]

Other Notes

Maximum number of entry points per scene is 128, ranging from 0 to 127. You can however use some unique scene props that could act as some sort of makeshift entry points. Lumos, Warband Script Enhancer v3.2.0, and cmpxchg8b, Modding Q&A, Modding Q&A, Modding Q&A and additional remark at Modding Q&A.

Formula used to calculate the number of agents a player gets at a battle's start. Caba`drin, Modding Q&A.

ti_on_agent_dismount, Caba`drin and dunde, Modding Q&A. ti_on_agent_dismount fires when horse dies, Caba`drin and Mammoet, Modding Q&A, so at both, Caba`drin, Modding Q&A

add_visitors_to_current_scene and entry_point_set_position, Vornne and dunde, Modding Q&A

Teams in Singleplayer, Caba`drin, Modding Q&A

Condition block check timing, GetAssista, Modding Q&A

mf_battle_mode, cmpxchg8b, Modding Q&A

ti_on_leave_area and ti_on_player_exit, Caba`drin and Somebody, Modding Q&A

Delay doesn't work for named triggers but rearm works fine, cmpxchg8b, Modding Q&A and Modding Q&A

Teams count SP and MP, Somebody, Modding Q&A. InVain also made some little test there, need to fetch note for that.

ti_on_agent_killed_or_wounded, Caba`drin, Modding Q&A

Bundle triggers (read comments along the whole page), Caba`drin, Modding Q&A

Teams in SP, Caba`drin, Modding Q&A

Adding list of triggers, Caba`drin, Modding Q&A

Adding triggers to Mission template always at top, _Sebastian_, Modding Q&A

maximum number teams in mission, dunde and Caba`drin, Modding Q&A

ti_on_item_dropped only mp, dunde, Modding Q&A

entry point limit, Lumos, Modding Q&Q

Some stuff explained already, check if all infos present, Somebody, Modding Q&A

ŝtrange ai behaviour, multiple discussions, Modding Q&A

no consequences after trigger, Swyter, Modding Q&A

open questions about spawning agent, Lav, Modding Q&A

entry points and entry number, Waldzios (credit), Modding Q&A

mt flags override player inventory, Lav, Modding Q&A

mp end map, Ikaguia, Modding Q&A

how much time is it (add also to module triggers if not already), The_dragon, Modding Q&A

listing triggers, Somebody, Modding Q&A

bundle triggers, kalarhan, Modding Q&A

some mission template stuff, kalarhan, Modding Q&A

no delays for engine events, _Sebastian_, Modding Q&A

hard-coded mission templates, kalarhan, Modding Q&A

list of triggers, kalarhan, Modding Q&A

entry points at mission templates, Khamukkamu and kalarhan, Modding Q&A

additional teams remark, Vornne, Modding Q&A

prevent save or quicksave mid-scene, kalarhan, Modding Q&A

Characters remove helmets in conversations, kalarhan, Modding Q&A

Override behaviour of some keys, kalarhan, Modding Q&A

list of triggers, kalarhan, Modding Q&A

scene_source flag, need to reread, Strange "set_visitor" error

charge flag, nijis and bryce777 (credit), Breaking the random encounter scene spawnpoints

Scene source people never wear hats? Yoshiboy, NPCs not wearing hats

Entry points limit, cmpxchg8b, [WB] Warband Script Enhancer v3.2.0

Working around 127 event limit, cmpxchg8b, [WB] Warband Script Enhancer v3.2.0

auto-calc battle, jacobhinds and kalarhan, Modding Q&A, Rabbit hole threads, Earendil redirect, Autocalc and Unit Levels. Get the normal links in the Forge Scrap Yard for better integration.